package com.pgytesting.mobilecertpay.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.pgytesting.mobilecertpay.dao.NaBusinessInformationDao;
import com.pgytesting.mobilecertpay.entity.NaSecret;
import com.pgytesting.mobilecertpay.dao.NaSecretDao;
import com.pgytesting.mobilecertpay.service.NaSecretService;
import com.pgytesting.mobilecertpay.util.RSAUtils;
import com.pgytesting.mobilecertpay.util.ResponseMassage;
import com.pgytesting.mobilecertpay.util.UtilMethod;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 公钥私钥日志表(NaSecret)表服务实现类
 *
 * @author makejava
 * @since 2019-05-10 11:46:58
 */
@Slf4j
@Service("naSecretService")
public class NaSecretServiceImpl implements NaSecretService {
    @Resource
    private NaSecretDao naSecretDao;

    @Resource
    NaBusinessInformationDao naBusinessInformationDao;


    /**
     * 通过ID查询单条数据
     *
     * @param paraMap 全部参数
     * @return 实例对象
     */
    @Override
    public Map<String, Object> queryById(Map<String, Object> paraMap) {
        NaSecret naSecret = new NaSecret();
        log.info("对账号类型进行动态检查");
        if (!UtilMethod.isEmpty(String.valueOf(paraMap.get("mobileNo")))){
            naSecret.setMobileNo(String.valueOf(paraMap.get("mobileNo")));
            if (!UtilMethod.isEmpty(String.valueOf(paraMap.get("merchantMail"))))
                naSecret.setMerchantMail(String.valueOf(paraMap.get("merchantMail")));
        }else if (!UtilMethod.isEmpty(String.valueOf(paraMap.get("merchantMail")))){
            naSecret.setMerchantMail(String.valueOf(paraMap.get("merchantMail")));
            if (!UtilMethod.isEmpty(String.valueOf(paraMap.get("mobileNo"))))
                naSecret.setMobileNo(String.valueOf(paraMap.get("mobileNo")));
        }else if(!UtilMethod.isEmpty(String.valueOf(paraMap.get("merchantId")))){
            log.info("判断获取类型为商户号");
            naSecret.setMerchantId(String.valueOf(paraMap.get("merchantId")));
        }else {
            return ResponseMassage.getResMassage("10001");
        }
        NaSecret naSecret1;
        try {
            naSecret1 = this.naSecretDao.queryById(naSecret);
        } catch (Exception e) {
            return ResponseMassage.getResMassage("20003");
        }
        Map<String, Object> resultMap = new LinkedHashMap<>();
        log.info("公钥私钥注册查询");
        if (naSecret1 != null) {
            if (UtilMethod.isEmpty(naSecret1.getPublicKey()) && (!UtilMethod.isEmpty(naSecret1.getMobileNo()) || !UtilMethod.isEmpty(naSecret1.getMerchantMail()))) {
                log.info("公钥为空,进行公钥私钥更新,拼接过滤参数");
                naSecret.setMerchantMail(UtilMethod.isEmpty(naSecret1.getMerchantMail()) ? naSecret.getMerchantMail() : naSecret1.getMerchantMail());
                naSecret.setMobileNo(UtilMethod.isEmpty(naSecret1.getMobileNo()) ? naSecret.getMobileNo() : naSecret1.getMobileNo());
                log.info("进行账号公钥私钥进行更新");
                this.update(UtilMethod.getKey(naSecret));
            }else {
                resultMap.put("publicKey", naSecret1.getPublicKey());
                return resultMap;
            }
        } else {
            this.insert(UtilMethod.getKey(naSecret));
        }
        resultMap.put("publicKey", naSecret.getPublicKey());
        return resultMap;
    }



    /**
     * 查询多条数据
     *
     * @param offset 查询起始位置
     * @param limit  查询条数
     * @return 对象列表
     */
    @Override
    public List<NaSecret> queryAllByLimit(int offset, int limit) {
        return this.naSecretDao.queryAllByLimit(offset, limit);
    }

    /**
     * 进行获取到的参数中的data进行解密
     *
     * 1、RSA加密最多只能支持117位的字符，如果超限了
     *      1、前端把所有数据进行分段加密，以递归方式对所有数据进行加密
     *      2、每段数据以字符串的形式进行数组或者字符串拼接
     *      3、然后在进行分段解密，拼接出解密后的数据
     * 2、后台获取私钥
     *      1、注册商户时，注册完成进行商户代码回填更新到秘钥日志表
     *      2、后面每次进行数据解密以商户代码进行查询过滤，查询到私钥进行解密
     *      3、只有初次注册获取公钥的时候才可以以手机号和邮箱共同获取
     *      4、注册成功后，获取公钥必须以商户代码进行获取，负责后台返回错误提示
     *
     * @param paraMap 参数
     * @return 对象列表
     */
    @Override
    public Map<String,Object> queryDecrypt(Map<String,Object> paraMap) {
        log.info("进行参数密文解密");
        // 进行私钥查询
        /**
         * 先等待商户注册搞定
         */
        return null;
    }

    /**
     * 新增数据
     *
     * @param naSecret 实例对象
     * @return 实例对象
     */
    @Override
    public NaSecret insert(NaSecret naSecret) {
        this.naSecretDao.insert(naSecret);
        return naSecret;
    }

    /**
     * 修改数据
     *
     * @param naSecret 实例对象
     * @return 实例对象
     */
    @Override
    public NaSecret update(NaSecret naSecret) {
        this.naSecretDao.update(naSecret);
        return this.naSecretDao.queryById(naSecret);
    }

    /**
     * 通过主键删除数据
     *
     * @param mobileNo 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(String mobileNo) {
        return this.naSecretDao.deleteById(mobileNo) > 0;
    }

    /**
     * 进行入参解密
     *
     * @return
     */
    @Override
    public JSONObject getDecrypt(Map<String, Object> paraMap){
        log.info("进行私钥获取");
        NaSecret naSecret = new NaSecret();
        String merchantMail = String.valueOf(paraMap.get("merchantMail"));
        if (UtilMethod.isEmpty(merchantMail)){
            log.info("非注册类请求，以商户ID进行数据解密");
            String merchantId = String.valueOf(paraMap.get("merchantId"));
            merchantMail = naBusinessInformationDao.queryMerchant(merchantId);
            if (UtilMethod.isEmpty(merchantMail)){
                log.info("未查询到商户ID对应的商户邮箱地址，解密数据失败");
                return null;
            }
        }
        naSecret.setMerchantMail(merchantMail);
        naSecret = naSecretDao.queryById(naSecret);
        String encryptionData;
        try {
            log.info("进行数据解密操作");
            encryptionData = RSAUtils.getSegDecryption(naSecret.getPrivateKey(), String.valueOf(paraMap.get("data")));
        }catch (Exception e){
            return null;
        }
        JSONObject json;
        try {
            log.info("进行参数转换");
            json = JSONObject.parseObject(encryptionData);
        }catch (Exception e){
            return null;
        }
        return json;
    }

}